<template>
  <el-row :gutter="10">
    <el-col :span="24" class="mb10">
      <el-button-group class="mr10" v-if="props.operations.length > 0">
        <el-button v-for="(button, index) in props.operations"
                   :v-bind="button"
                   :type="button.type"
                   :icon="button.icon"
                   @click="button.click"
        >{{ button.label }}
        </el-button>
      </el-button-group>
      <slot name="operations"></slot>
      <div style="float: right">
        <el-popover placement="bottom" :width="200" trigger="click" v-if="state.isColumnShow">
          <el-row :gutter="15">
            <el-col v-for="(item, index) in state.columns">
              <el-checkbox v-model="state.columns[index].checked"
              >{{ item.label }}
              </el-checkbox>
              <template v-for="(itemc, indexc) in item.children">
                <el-checkbox v-model="item.children[indexc].checked">{{ itemc.label }}</el-checkbox>
              </template>
            </el-col>
          </el-row>
          <template #reference>
            <el-button icon="elementOperation"></el-button>
          </template>
        </el-popover>
      </div>
    </el-col>
    <el-col :span="24">
      <el-table :data="state.data"
                v-model="modelValue"
                v-loading="state.isLoading"
                @selection-change="proxy.$emit('selection-change', $event)"
                :empty-text="state.emptyText"
                sortable="custom"
                @sort-change="sortChange"
                :default-sort="state.defaultSort"
                @cell-click="proxy.$emit('cell-click', $event)"
                @select="proxy.$emit('select', $event)"
                :highlight-current-row="props.highlight"
                id="printRef"
                :height="state.tableHeight"
                :summary-method="table._initTotal"
                :show-summary="props.isShowSummary"
                :timeOut="props.timeOut"
                ref="tableRef"
                :header-cell-style="headerCellStyle"
                :cell-style="{ borderColor: '#9aa1ac' }"
                class="tableClass"
                @row-click="proxy.$emit('row-click', $event)">
        <el-table-column label="" width="40" v-if="props.isRadio" fixed>
          <template #default="scope">
            <el-radio v-model="state.radio"
                :label="scope.$index"
                @change="proxy.$emit('radio', scope.row)"
                style="color: #fff; padding-left: 22px"></el-radio>
          </template>
        </el-table-column>
        <el-table-column v-if="props.selection" type="selection" align="center"></el-table-column>
        <el-table-column label="序号" width="60" align="center" fixed>
          <template #default="scope">
            <span>{{
                scope.$index +
                (state.param.pageNo - 1) * state.param.pageSize +
                1
              }}
            </span>
          </template>
        </el-table-column>
        <template v-for="(item, index) in state.columns" :key="item.id">
          <el-table-column
              v-if="item.children.length > 0 && item.checked"
              :type="item.type"
              :prop="item.prop"
              :label="item.label"
              :align="item.align"
              :header-align="item.headerAlign"
              :width="item.width"
              :min-width="item.minWidth"
              :sortable="item.sortable"
              :show-overflow-tooltip="item.tooltip"
              :fixed="item.fixed"
              :sort-method="
              (a, b) => {
                return a[item.prop] - b[item.prop];
              }
            "
          >
            <template v-for="(itemc, indexc) in item.children" :key="itemc.id">
              <el-table-column
                  v-if="itemc.checked"
                  :key="itemc.id"
                  :type="itemc.type"
                  :prop="itemc.prop"
                  :label="itemc.label"
                  :align="itemc.align"
                  :header-align="itemc.headerAlign"
                  :width="itemc.width"
                  :min-width="itemc.minWidth"
                  :sortable="itemc.sortable"
                  :formatter="itemc.formatter"
                  :show-overflow-tooltip="itemc.tooltip"
                  :fixed="itemc.fixed"
                  :sort-method="
                  (a, b) => {
                    return a[itemc.prop] - b[itemc.prop];
                  }
                "
              >
                <template #default="scope">
                  <span v-if="itemc.formatter">{{
                      item.formatter(scope.row)
                    }}</span>
                  <slot
                      v-else-if="itemc.slot"
                      :name="itemc.slot"
                      :row="scope.row"
                      :index="scope.$index"
                  />
                  <span v-else>{{ scope.row[itemc.prop] }}</span>
                </template>
              </el-table-column>
            </template>
          </el-table-column>

          <el-table-column
              v-else
              v-if="item.checked"
              :type="item.type"
              :prop="item.prop"
              :label="item.label"
              :align="item.align"
              :header-align="item.headerAlign"
              :width="item.width"
              :min-width="item.minWidth"
              :sortable="item.sortable"
              :show-overflow-tooltip="item.tooltip"
              :fixed="item.fixed"
              :sort-method="
              (a, b) => {
                return a[item.prop] - b[item.prop];
              }
            "
          >
            <template #default="scope">
              <span v-if="item.formatter">{{ item.formatter(scope.row) }}</span>
              <slot
                  v-else-if="item.slot"
                  :name="item.slot"
                  :row="scope.row"
                  :index="scope.$index"
              />
              <span v-else>{{ scope.row[item.prop] }}</span>
            </template>
          </el-table-column>
        </template>
      </el-table>
      <template v-if="state.isPage">
        <el-pagination
            @size-change="onHandleSizeChange"
            @current-change="onHandleCurrentChange"
            class="mt15"
            :pager-count="5"
            :page-sizes="state.pageSizes"
            v-model:current-page="state.param.pageNo"
            background
            v-model:page-size="state.param.pageSize"
            layout="total, sizes, prev, pager, next, jumper"
            :total="state.param.count"
        >
        </el-pagination>
      </template>
    </el-col>
  </el-row>
</template>
<script lang="ts" setup>
import {
  ref,
  getCurrentInstance,
  reactive,
  defineProps,
  defineExpose,
  watch,
} from "vue";
import request from "/@/utils/request";
import {Local} from "/@/utils/storage";
import printJs from "print-js";

const {proxy}: any = getCurrentInstance();
const tableRef = ref();
const headerCellStyle = {
  background: '#eef1f6',
  color: '#606266',
  borderColor: '#9aa1ac',
  height: '40px',
  lineHeight: '40px',
}
const props = defineProps({
  url: {
    type: String,
    default: "",
  },
  totalUrl: String,
  // 数据列表
  data: {
    type: Array,
    default: [],
  },
  isShowData: {
    type: Boolean,
    default: false,
  },
  // 需要展示的列 === prop：列数据对应的属性，label：列名，align：对齐方式，width：列宽, // table 表格的控制参数
  columns: {
    type: Array,
    default: [],
  },
  //操作按钮
  operations: {
    type: Array,
    default: [],
  },
  //查询条件
  where: {
    type: Object,
    default: {},
  },
  //是否分页
  isPage: {
    type: Boolean,
    default: true,
  },
  //是否展示动态列按钮
  isColumnShow: {
    type: Boolean,
    default: false,
  },
  //延时加载
  timeOut: {
    type: Number,
    default: 100,
  },
  //是否加载
  isLoading: {
    type: Boolean,
    default: false,
  },
  //是否在表尾显示合计行
  isShowSummary: {
    type: Boolean,
    default: false,
    // require: false,
  },
  //emptyText
  emptyText: {
    type: String,
    default: "暂无数据",
    require: false,
  },
  //是否开启多选
  selection: {
    type: Boolean,
    default: false,
  },
  limit: {
    type: Number,
    default: 20,
  },
  //选择方式（仅用于多选时）
  type: {
    type: String,
    default: "select", //select：多选    radio：单选
    require: false,
  },
  param: {
    page: 1,
    limit: 20,
    count: 10,
  },
  page: 0,
  modelValue: String,
  dataTime: {
    type: String,
    default: "",
  },
  isSortRequest: {
    type: Boolean,
    default: false,
  },
  //表格高度
  tableHeight: {
    type: Number,
    default: 330,
  },
  //表格高度
  heightIsFixed: {
    type: Boolean,
    default: false,
  },
  // 是否高亮
  highlight: {
    type: Boolean,
    default: false,
  },
  isTitleConvert: {
    type: Boolean,
    default: true,
  },
  isRadio: {
    type: Boolean,
    default: false,
  },
  //默认排序是否开启
  defaultSort: {
    type: Boolean,
    default: true
  }
});
const state = reactive({
  data: [],
  param: {
    queryJson: "",
    pageNo: 1,
    pageSize: 20,
    count: 0,
  },
  radio: "",
  isPage: true,
  isShowData: false,
  isColumnShow: false,
  isLoading: true,
  timeOut: 0,
  columns: [] as Array<Object>,
  operations: [] as Array<Object>,
  emptyText: "",
  pageSizes: [10, 20, 50, 100],
  tableTitle: "",
  columnLabel: "",
  columnOrder: "",
  isSort: "",
  sortName: "",
  tableHeight: 0,
  totalRow: "",
  dataTime: "",
  isTitleConvert: true,
  defaultSort: {}
});
const _tableInit = () => {
  state.isPage = props.isPage;
  state.isColumnShow = props.isColumnShow;
  state.isShowData = props.isShowData;
  state.timeOut = props.timeOut;
  if (props.heightIsFixed) {
    state.tableHeight = props.tableHeight;
  } else {
    state.tableHeight = window.innerHeight - props.tableHeight;
  }
  state.isTitleConvert = props.isTitleConvert;
  if (props.defaultSort) {
    state.defaultSort = {
      prop: props.where.orderColumn,
      order: props.where.orderFormat + 'ending',
    }
  }
  _columnInit();
  setTimeout(() => {
    loadData();
  }, state.timeOut);
  sortChange("");
};
proxy.$nextTick(() => {
  proxy.$refs.tableRef.doLayout();
});
//加载数据
const loadData = () => {
  if (!state.isShowData) {
    state.data = props.url;
    state.isLoading = false;
    return;
  }
  state.isLoading = true;
  state.emptyText = "加载中，请稍后...";
  Object.assign(state.param, props.where);
  if (proxy.$wigem.isEmpty(props.url)) {
    state.data = props.data;
    state.isLoading = false;
    return;
  }
  request({
    url: props.url,
    method: "get",
    params: state.param,
  }).then((res) => {
    if (res) {
      if (proxy.$wigem.isEmpty(res.data["list"])) {
        state.data = res.data;
        if (state.isPage) {
          state.param.count = res.count;
        }
      } else {
        state.data = res.data.list;
        if (state.isPage) {
          state.param.count = res.data.total;
        }
      }
      proxy.$emit("data-count", res.count);
      state.data.map((item) => {
        for (let i in item) {
          if (item[i] == null || item[i] == undefined) {
            item[i] = "-";
          }
        }
      });

      if (props.isShowSummary == true) {
        state.totalRow = res.totalRow;
        table._initTotal;
      }
      proxy.$emit("data-totalRow", res.totalRow);
    }
    state.emptyText = "暂无数据";
    setTimeout(() => {
      state.isLoading = false;
    }, state.timeOut);
  }).catch((error) => {
    state.emptyText = "暂无数据";
    state.isLoading = false;
  });
};

const load = () => {
  state.param.pageSize = 20;
  state.param.pageNo = 1;
  loadData();
};
const numberToCurrencyNo = (value: any) => {
  if (!value) return "0.00";

  value = (Math.round(value * 100) / 100).toFixed(2) + "";
  // 获取整数部分
  const intPart = Math.trunc(value);
  // 整数部分处理，增加,
  const intPartFormat = intPart
      .toString()
      .replace(/(\d)(?=(?:\d{3})+$)/g, "$1,");
  // 预定义小数部分
  let floatPart = "";
  // 将数值截取为小数部分和整数部分
  const valueArray = value.toString().split(".");
  if (valueArray.length === 2) {
    // 有小数部分
    floatPart = valueArray[1].toString(); // 取得小数部分
    return intPartFormat + "." + floatPart;
  }
  return intPartFormat + floatPart;
};

const table = {
  _initTotal: (params: any) => {
    proxy.$emit("total", params);

    if (proxy.$wigem.isEmpty(state.totalRow)) {
      return [];
    }
    let arr = state.totalRow;
    const {columns, data} = params;
    //默认第一格内容为合计
    const sums: string[] = ["", "合计"];
    columns.forEach((column: any, index: any) => {
      if (index === 1) {
        return;
      }
      if (arr != "") {
        if (column.property == undefined) {
          return;
        }
        let field = column.property;

        let fieldValue = "";
        let found: Boolean = false;
        Object.keys(columnRender).forEach(key => {
          if (proxy.$wigem.isEmpty(arr[field])) {
            sums[index] = columnRender.Null();
            return;
          }

          // 获取键的长度（因为键已经是字符串，所以直接获取其长度）
          const keyLength = key.length;
          if (field.slice(-keyLength) == key) {
            fieldValue = columnRender[key](arr[field]);
            found = true;
          }
        });

        if (!found) {
          fieldValue = arr[field];
        }

        sums[index] = fieldValue;
      }
    });
    return sums;
  }
}

const columnRender = {
  Null: () => {
    return "-";
  },
  Rate: (str: string) => {
    return str + "%";
  },
  Percent: (str: string) => {
    return str + "%";
  },
  Period: (str: string) => {
    return numberToCurrencyNo(str);
  },
  Acc: (str: string) => {
    return numberToCurrencyNo(str);
  },
  Increment: (str: string) => {
    return numberToCurrencyNo(str);
  },
}
//重新加载
const reload = () => {
  if (!state.isLoading) {
    state.isLoading = false;
    loadData();
  }
};
// 分页改变
const onHandleSizeChange = (val: number) => {
  state.param.pageSize = val;
  loadData();
};
// 分页改变
const onHandleCurrentChange = (val: number) => {
  state.param.pageNo = val;
  loadData();
};
const ascending_code = "ascending";
const desc_code = "desc";
const ascending_str = "升序";
const desc_str = "降序";
const sortChange = (sortOption) => {
  state.dataTime = props.dataTime;
  state.columnOrder =
      props.where.orderFormat == desc_code ? desc_str : ascending_str;
  let orderColumn = props.where.orderColumn;
  if (!proxy.$wigem.isEmpty(sortOption)) {
    state.columnOrder =
        sortOption.order == ascending_code ? ascending_str : desc_str;
    orderColumn = sortOption.prop;
  }
  getOrderColumnLabel(orderColumn);
  if (!proxy.$wigem.isEmpty(sortOption)) {
    if (props.isSortRequest) {
      props.where["orderColumn"] = sortOption.prop;
      props.where["orderFormat"] =
          state.columnOrder == ascending_str
              ? ascending_code.slice(0, 3)
              : desc_code;
      load();
    }
    proxy.$emit("sort-change", sortOption);
  }
};
//根据prop获取字段label
const getOrderColumnLabel = (prop: string) => {
  let cloumnObj = state.columns;
  cloumnObj.forEach((item: Object, index: Number) => {
    if (item.prop == prop) {
      state.columnLabel = item.label.replace(/（[^)]*）/g, "");
    }
    if (item.children) {
      item.children.forEach((itemc: Object, indexc: Number) => {
        if (item.label == "企业数量" && itemc.prop == prop) {
          state.columnLabel = `${itemc.label}`;
        } else if (itemc.prop == prop) {
          state.columnLabel = `${item.label.replace(/（[^)]*）/g, "")}${
              itemc.label
          }`;
        }
      });
    }
  });
};
//导出数据
/**
 * @name 导出表格数据
 */

const expertTable = (name?: String): void => {
  let elementPlusTable = {
    tableName: name || "elementTable",
    title: state.tableTitle,
    url: props.url.substring(4),
    isPage: props.isPage,
    cols: props.columns,
    queryJson: state.param,
  };
  request({
    url: "/api/approve/export/excel/table",
    method: "post",
    data: elementPlusTable,
    responseType: "blob",
  }).then((res) => {
    let url = window.URL.createObjectURL(
        new Blob([res], {type: "application/vnd.ms-excel"})
    );
    let link = document.createElement("a");
    link.style.display = "none";
    link.href = url;
    link.setAttribute("download", elementPlusTable.tableName + ".xlsx");
    document.body.appendChild(link);
    link.click();
  });
};


//字段初始化
const _columnInit = () => {
  state.columns = [];
  props.columns.forEach((item: Object, index: Number) => {
    let dfop: Object = {
      headerAlign: "center",
      align: "right",
      label: "",
      prop: "",
      dictionaryCode: "",
      type: "",
      width: null,
      //固定列
      fixed: false,
      //是否开启排序
      sortable: false,
      //格式化
      formatter: false,
      //插槽名称
      slot: false,
      //最小宽度
      minWidth: "",
      //超出宽度显示提示
      tooltip: true,
      checked: true,
      children: [],
    };
    let dfopc = dfop;
    let dfot = Object.assign({}, dfop, item);
    if (dfot.children.length > 0) {
      item.children.forEach((itemc: Object, indexc: Number) => {
        dfot.children[indexc] = Object.assign({}, dfopc, itemc);
      });
    }
    if (!!dfot.dictionaryCode) {
      dfot.formatter = (row, column) => {
        let dictionaryAllData = Local.get("dictionaryData");
        let data: Object = dictionaryAllData[dfot.dictionaryCode];
        let obj: Object = {};
        for (let key in data) {
          obj[data[key]["value"]] = data[key]["text"];
        }
        return obj[row[dfot.prop]];
      };
    }
    //强制居中对齐
    dfot.align = "center";
    state.columns.push(dfot);
  });
};
_tableInit();
watch(
    () => [props.dataTime, props.isShowData],
    (n, o) => {
      sortChange("");
    }
);
defineExpose({
  _tableInit,
  load,
  reload,
  expertTable
});
</script>
<style>
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

.el-table--border th.gutter:last-of-type {
  display: table-cell !important;
  width: 17px !important;
}

/* 解决合计行错位问题 */
.el-table__footer > tbody tr::after {
  content: "";
  width: 17px;
}

.el-table__body-wrapper {
  z-index: 1;
}

.el-table__footer-wrapper tbody td.el-table__cell,
.el-table__header-wrapper tbody td.el-table__cell {
  z-index: 2;
  border-bottom: 0;
}

.el-table__footer-wrapper {
  margin-top: -2px;
}

.changeTypeface {
  font-weight: 700;
  font-size: large;
}

.textCentered {
  text-align: center;
}

::v-deep .el-table__fixed {
  height: 100% !important;
}
</style>
<style scoped>
.tableClass {
  border: 0.5px solid black;
  border: none;
}

::v-deep .el-input__inner {
  color: #000 !important;
}

::v-deep .el-table th.gutter {
  /*
  * 解决element-ui 表格篡位的问题 👇
  */
  display: table-cell !important;
}

::v-deep .el-radio__label {
  display: none;
}
::v-deep .el-table__body tr,
.el-table__header tr {
  height: 50px; /* 设置行高为 40px */
  line-height: 50px; /* 确保文本垂直居中 */
}
::v-deep .el-table__cell{
  border-color: #c3c2c2 !important;
  border-right: none;
}
::v-deep .el-table__header{
  border-top: 0.5px solid #c3c2c2;
  border-left: 0.5px solid #c3c2c2;
  border-right: 0.5px solid #c3c2c2;
}
</style>
